package com.ytjj.qmyx.admin.controller;

import com.ytjj.common.api.CommonPage;
import com.ytjj.common.api.CommonResult;
import com.ytjj.common.api.ResultCode;
import com.ytjj.common.constants.CopyWriterConstant;
import com.ytjj.common.constants.RedisConstants;
import com.ytjj.common.exception.ApiException;
import com.ytjj.common.service.RedisService;
import com.ytjj.common.utils.CopyWriterConfigUtil;
import com.ytjj.qmyx.admin.annotation.OperLog;
import com.ytjj.qmyx.admin.constants.SysLogConstants;
import com.ytjj.qmyx.admin.mapper.AdminMapper;
import com.ytjj.qmyx.admin.mapper.DeptMapper;
import com.ytjj.qmyx.admin.model.Admin;
import com.ytjj.qmyx.admin.model.Menu;
import com.ytjj.qmyx.admin.model.Role;
import com.ytjj.qmyx.admin.model.request.AdminRequest;
import com.ytjj.qmyx.admin.model.request.BankerRequest;
import com.ytjj.qmyx.admin.model.request.LoginRequest;
import com.ytjj.qmyx.admin.model.request.UpdateRoleRequest;
import com.ytjj.qmyx.admin.model.response.ButtonViewsResponse;
import com.ytjj.qmyx.admin.model.response.MenuViewsResponse;
import com.ytjj.qmyx.admin.service.AdminService;
import com.ytjj.qmyx.admin.service.BankerService;
import com.ytjj.qmyx.admin.service.imService.ImServiceUserService;
import com.ytjj.qmyx.admin.utils.TreeUtil;
import com.ytjj.qmyx.admin.utils.UserUtil;
import com.ytjj.qmyx.mall.model.Banker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 管理员
 */
@Slf4j
@RestController
@RequestMapping("/admin")
public class AdminController {

    @Resource
    private RedisService redisService;

    @Autowired
    private AdminService adminService;

    @Autowired
    private BankerService bankerService;

    @Autowired
    private ImServiceUserService imServiceUserService;
    @Resource
    private DeptMapper DeptMapper;
    @Resource
    private AdminMapper adminMapper;

    @Resource
    private CopyWriterConfigUtil copyWriterConfigUtil;
    @Value("${accountErrNum:5}")
    private Integer accountErrNum;//试错次数
    @Value("${lockSec:30}")
    private Integer lockSec;//锁定时间，单位：分
    @Value("${withinTime:5}")
    private Integer withinTime;//多长时间范围内试错次数，单位：分

    private final String administrator = "admin@admin.com";

    /**
     * 管理员登陆
     *
     * @param loginRequest
     * @return
     */

    @PostMapping("/login")
    @OperLog(operModule = "登录模块", operDesc = "后台登陆", operType = SysLogConstants.LOGIN_OPERATION)
    public CommonResult login(@RequestBody LoginRequest loginRequest) {
        String redisAccountStatus = redisService.get(RedisConstants.ACCOUNT_STATUS + loginRequest.getTel());
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(redisAccountStatus) && "0".equals(redisAccountStatus)) {
            throw new ApiException("账号或密码输入错误次数过多，请稍后重试");
        }
        // 获取redis中的验证码
        String redisCode = redisService.get(loginRequest.getVerKey());
        String verCode = loginRequest.getVerCode();
        // 判断验证码
        if (Strings.isEmpty(loginRequest.getVerCode()) || !verCode.trim().toLowerCase().equals(redisCode)) {
            throw new ApiException("验证码不正确");
        }
        //添加用户认证信息
        String tel = loginRequest.getTel();
        String pwd = loginRequest.getPwd();
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(tel, pwd, verCode);

        //对后台管理员账号进行验证
        Admin adminAccount = adminService.getAdminStatus(tel);
        if(adminAccount != null && adminAccount.getStatus() == 0) {
            return CommonResult.failed("您的账号存在异常，请联系管理员！");
        }
        try {
            if(subject.isAuthenticated()){
                subject.logout();
            }
            subject.login(usernamePasswordToken);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            //记录错误次数信息
            doHandleUserNameAndPwdIsErr(tel);
            return CommonResult.failed(copyWriterConfigUtil.getCopyWriterValue(CopyWriterConstant.ACCOUNT_PASSWORD_FAILED));
        } catch (AuthorizationException e) {
            e.printStackTrace();
            return CommonResult.failed(copyWriterConfigUtil.getCopyWriterValue(CopyWriterConstant.NO_PERMISSION));
        }
        //登录成功清除redis中错误次数信息
        doHandleClearErrInfo(tel);
        Session session = subject.getSession();
        log.debug("sessionInfos:{[id=" + session.getId() + "],[host=" + session.getHost() + "],[timeout=" + session.getTimeout() + "]}");

//        redisService.set(ImRedisKeyConstant.IM_SERVICE_EMAIL + adminAccount.getEmail(), adminAccount.getName());

        //判断是否是客服部的角色
//        if (null != adminAccount.getDeptId()){
//            Dept dept = DeptMapper.selectDept(adminAccount.getDeptId());
//            if ("客服部".equals(dept.getDeptName())){
//                imServiceUserService.insertOrUpdate(loginRequest.getTel());//判断imServiceUser表中是否有该账号的数据
//            }
//        }

        return CommonResult.success(session.getId(), "登录成功！");
    }

    private void doHandleClearErrInfo(String tel) {
        redisService.delete(RedisConstants.LOGIN_ERR_NUM + tel);
    }

    private void doHandleUserNameAndPwdIsErr(String tel) {
        String errNumStr = redisService.get(RedisConstants.LOGIN_ERR_NUM + tel);
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(errNumStr)) {
            Integer errNum = Integer.parseInt(errNumStr);
            if (errNum + 1 > accountErrNum) {
                redisService.set(RedisConstants.LOGIN_ERR_NUM + tel, "0");
                redisService.set(RedisConstants.ACCOUNT_STATUS + tel, "0");
                redisService.expire(RedisConstants.ACCOUNT_STATUS + tel, lockSec * 60);
                throw new ApiException("账户密码输入错误次数过多，请稍后重试");
            }
            redisService.set(RedisConstants.LOGIN_ERR_NUM + tel, String.valueOf(errNum + 1));
        }else {
            redisService.set(RedisConstants.LOGIN_ERR_NUM + tel, "1");
            redisService.expire(RedisConstants.LOGIN_ERR_NUM + tel, withinTime * 60);
        }
    }

    /**
     * 根据token查询用户的权限树
     *
     * @return
     */
    @GetMapping(value = "/getMenuTree")
    public CommonResult getMenuTree(HttpServletRequest request) {
        String userId=UserUtil.getPrincipal();
        log.debug("getMenuTree,userId={}",userId);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(userId)) {
            List<Menu> menuList = null;
            Map<String, Object> data = new HashMap<>();
            if (administrator.equals(userId)) {
                menuList = adminService.getAdminMenuList();                 // 管理员最大账号可以看到所有的菜单
            } else {
                menuList = adminService.getMenuAllByTel(userId);
            }
            Admin admin = adminService.getAdminByEmail(userId);
            admin.setPwd(null);
            data.put("userInfo", admin);

            if (CollectionUtils.isEmpty(menuList)) {
                return CommonResult.failed(ResultCode.UNAUTHORIZED, "初始化菜单失败，请检查权限配置！");
            }
            // 进一步封装数据
            // 菜单
            List<Menu> menus = menuList.stream().filter(item -> item.getType() == 1).collect(Collectors.toList());
            List<MenuViewsResponse> menuTreeResponses = TreeUtil.getRouteListData(menus);
            List<MenuViewsResponse> treeData = TreeUtil.getRouteTreeList(menuTreeResponses);
            data.put("treeData", treeData);

            // 按钮
            List<Menu> buttons = menuList.stream().filter(item -> item.getType() == 2 && item.getIsPermission() == 1).collect(Collectors.toList());
            List<ButtonViewsResponse> buttonData = this.getButtonViewsData(buttons);
            data.put("buttonData", buttonData);

            return CommonResult.success(data, "登录成功！");
        }
        return CommonResult.failed(ResultCode.UNAUTHORIZED);
    }

    /**
     * 登出
     *
     * @return
     */
    @GetMapping(value = "/logout")
    public CommonResult logout() {
        return CommonResult.success(null);
    }

    /**
     * 查询所有管理员
     *
     * @param admin
     * @return
     */
    @RequiresPermissions("admin:list")
    @PostMapping("/list")
    public CommonResult list(@RequestBody AdminRequest admin) {
        CommonPage<Admin> pageList = adminService.selectList(admin);
        return CommonResult.success(pageList);
    }

    /**
     * 根据条件查询所有管理员
     *
     * @param admin
     * @return
     */
    @PostMapping("/getAllAdmin")
    public CommonResult<List<Admin>> getAllAdmin(@RequestBody AdminRequest admin) {
        List<Admin> list = adminMapper.getAllAdmin(admin);
        return CommonResult.success(list);
    }

    /**
     * 添加管理员
     *
     * @param admin
     * @return
     */
    @RequiresPermissions("admin:addAdmin")
    @PostMapping("/addAdmin")
    @OperLog(operModule = "用户模块", operDesc = "添加管理员", operType = SysLogConstants.OPERATION_ADD)
    public CommonResult<Admin> addAdmin(@RequestBody Admin admin) {
        adminService.addAdmin(admin);
        return CommonResult.success();
    }

    /**
     * 根据管理员id获取实体
     *
     * @param id
     * @return
     */
    @GetMapping(value = "/getAdmin")
    public CommonResult<Admin> getAdmin(@RequestParam("adminId") Integer id) {
        Admin admin = adminService.selectAdminById(id);
        return CommonResult.success(admin);
    }


    /**
     * 修改指定管理员信息
     *
     * @param admin
     * @return
     */
    @RequiresPermissions("admin:updateAdmin")
    @PostMapping("/updateAdmin")
    @OperLog(operModule = "用户模块", operDesc = "修改指定管理员信息", operType = SysLogConstants.OPERATION_UPDATE)
    public CommonResult updateAdmin(@RequestBody Admin admin) {
        int count = adminService.updateAdmin(admin);
        if (count > 0) {
            return CommonResult.success(count);
        }
        return CommonResult.failed();
    }

    @GetMapping(value = "/deletesAdmin")
    @OperLog(operModule = "账户模块", operDesc = "注销账户", operType = SysLogConstants.OPERATION_UPDATE)
    public CommonResult deleteAdmins(Integer id){
        return CommonResult.success(adminService.deleteAdmins(id));
    }

    @PostMapping("/updateSelfPwd")
    @OperLog(operModule = "用户模块", operDesc = "修改管理员自己密码", operType = SysLogConstants.OPERATION_UPDATE)
    public CommonResult updateSelfPwd(@RequestBody Admin admin, HttpServletRequest request) {
        //1.判断admin密码是否为空
        if (Objects.isNull(admin) || org.apache.commons.lang3.StringUtils.isBlank(admin.getPwd())) {
            return CommonResult.failed("密码不能为空");
        }
        //2.判断当前用户是否是自己
        if (!checkCurUser(admin, request)) {
            return CommonResult.failed(ResultCode.UNAUTHORIZED);
        }
        int count = adminService.updateAdmin(admin);
        if (count > 0) {
            return CommonResult.success(count);
        }
        return CommonResult.failed();
    }

    /**
     * 比较是否当前操作用户自己
     * @param request
     * @return true-匹配 false-不匹配
     */
    private boolean checkCurUser(Admin admin, HttpServletRequest request) {
        String sessionId = SecurityUtils.getSubject().getSession().getId().toString();
        Admin loginAdmin = UserUtil.getUserInfoBySessionId(sessionId);
        if(null==loginAdmin||null==admin){
            return false;
        }
        if (loginAdmin.getId().equals(admin.getId())) {
            return true;
        }
        return false;
    }

    /**
     * 删除指定管理员信息
     *
     * @param id
     * @return
     */
    @PostMapping("/deleteAdmin")
    @OperLog(operModule = "用户模块", operDesc = "删除指定管理员信息", operType = SysLogConstants.OPERATION_DELETE)
    public CommonResult deleteAdmin(@RequestParam("adminId") Integer id) {
        int count = adminService.deleteAdmin(id);
        if (count > 0) {
            return CommonResult.success(count);
        }
        return CommonResult.failed();
    }

    /**
     * 停用/启用 管理员信息
     *
     * @param id
     * @return
     */
    @RequiresPermissions("admin:updateStatus")
    @GetMapping("/updateStatus")
    @OperLog(operModule = "用户模块", operDesc = "停用/启用管理员信息", operType = SysLogConstants.OPERATION_UPDATE)
    public CommonResult updateStatus(@RequestParam("adminId") Integer id) {

        Admin admin = adminService.selectAdminById(id);
        int count = adminService.updateStatus(admin);
        if (count > 0) {
            return CommonResult.success(count);
        }
        return CommonResult.failed();
    }

    /**
     * 根据用户id查询角色信息
     *
     * @param adminId
     * @return
     */
    @RequiresPermissions("admin:role")
    @GetMapping(value = "/role")
    public CommonResult<List<Role>> getRoleList(@RequestParam Integer adminId) {
        List<Role> roleList = adminService.getRoleListByAdminId(adminId);
        return CommonResult.success(roleList);
    }

    /**
     * 给用户分配角色
     *
     * @param updateRoleRequest
     * @return
     */
    @PostMapping(value = "/role/update")
    @OperLog(operModule = "角色模块", operDesc = "给用户分配角色", operType = SysLogConstants.OPERATION_UPDATE)
    public CommonResult updateRole(@RequestBody UpdateRoleRequest updateRoleRequest) {
        int count = adminService.updateRole(updateRoleRequest);
        if (count >= 0) {
            return CommonResult.success(count);
        }
        return CommonResult.failed();
    }


    // -------------------------------------------------------- 供应商 -----------------------------------------------------------------------------

    /**
     * 查询店家
     *
     * @param bankerRequest
     * @return
     */
//    @RequiresPermissions("admin:bankerList")
    @PostMapping("/bankerList")
    public CommonResult bankerList(@RequestBody BankerRequest bankerRequest) {
//        String userId=UserUtil.getPrincipal();
//        Admin admin = adminService.getAdminByEmail(userId);
        Admin admin = new Admin();
        return CommonResult.success(adminService.bankerLists(bankerRequest, admin));
    }

    @RequiresPermissions("admin:updateHoliday")
    @GetMapping("/updateHoliday")
    public CommonResult updateHoliday(@RequestParam Integer id) {
        adminService.updateHoliday(id);
        return CommonResult.success();
    }

    /**
     * @Description 供应商上架
     *
     *
     * @Version 1.0
     **/
    @GetMapping("/bankerPutaway")
    public CommonResult bankerPutaway(@RequestParam("id") Integer id) {
        adminService.bankerPutaway(id);
        return CommonResult.success(ResultCode.SUCCESS);
    }

    /**
     * 查询所有店家
     *
     * @return
     */
    @GetMapping("/selectBankers")
    public CommonResult selectBankers() {
        List<Banker> list = bankerService.selectBankers();
        return CommonResult.success(list);
    }

    /**
     * 根据店家id获取实体
     *
     * @param id
     * @return
     */
    @GetMapping(value = "getBanker")
    public CommonResult<Banker> getBanker(@RequestParam Integer id) {
        Banker banker = adminService.selectBankerById(id);
        return CommonResult.success(banker);
    }


    /**
     * 添加店家管理员
     *
     * @param banker
     * @return
     */
    @RequiresPermissions("admin:addBanker")
    @PostMapping("/addBanker")
    @OperLog(operModule = "供应商模块", operDesc = "添加店家管理员", operType = SysLogConstants.OPERATION_ADD)
    public String addBanker(@RequestBody BankerRequest banker) {
        return adminService.newAddBanker(banker);
    }

    /**
     * 修改供应商
     *
     * @param banker
     * @return
     */
    @RequiresPermissions("admin:updateBanker")
    @PostMapping("/updateBanker")
    @OperLog(operModule = "供应商模块", operDesc = "修改供应商", operType = SysLogConstants.OPERATION_UPDATE)
    public CommonResult updateBanker(@RequestBody BankerRequest banker) {
        adminService.updateBanker(banker);
        return CommonResult.success(ResultCode.SUCCESS);
    }

    /**
     * 删除指定店家(废弃接口)
     *
     * @param id
     * @return
     */
    @GetMapping("/deleteBanker")
    @OperLog(operModule = "供应商模块", operDesc = "删除指定店家", operType = SysLogConstants.OPERATION_DELETE)
    public CommonResult deleteBanker(@RequestParam Integer id) {
        int count = adminService.deleteBanker(id);
        if (count > 0) {
            return CommonResult.success(count);
        }
        return CommonResult.failed();
    }

    /**
     * 停用/启用
     *
     * @param id
     * @return
     */
    @RequiresPermissions("admin:updateStatusBanker")
    @GetMapping("/updateStatusBanker")
    @OperLog(operModule = "供应商模块", operDesc = "停用/启用店家", operType = SysLogConstants.OPERATION_DELETE)
    public String updateStatusBanker(@RequestParam("id") Integer id,
                                           @RequestParam("status") Integer status,
                                           @RequestParam(required = false, name = "msg") String msg) {
        return adminService.newUpdateStatusBanker(id, status, msg);
    }

    /**
     * 根据店家id查询角色信息
     *
     * @param bankerId
     * @return
     */
    @GetMapping(value = "/bankerRole")
    public CommonResult<List<Role>> getbankerRoleList(@RequestParam Integer bankerId) {
        List<Role> roleList = adminService.getRoleListByBankerId(bankerId);
        return CommonResult.success(roleList);
    }

    /**
     * 给用户分配角色bankerSite
     *
     * @param updateRoleRequest
     * @return
     */
    @PostMapping(value = "/bankerRole/update")
    @OperLog(operModule = "供应商模块", operDesc = "给用户分配角色", operType = SysLogConstants.OPERATION_ADD)
    public CommonResult updateBankerRole(@RequestBody UpdateRoleRequest updateRoleRequest) {
        int count = adminService.updateBankerRole(updateRoleRequest);
        if (count >= 0) {
            return CommonResult.success(count);
        }
        return CommonResult.failed();
    }

    private List<ButtonViewsResponse> getButtonViewsData(List<Menu> menus) {
        if (CollectionUtils.isEmpty(menus)) {
            return null;
        }
        List<ButtonViewsResponse> buttonViews = new ArrayList<>();
        for (Menu menu : menus) {
            ButtonViewsResponse buttonViewsResponse = new ButtonViewsResponse();
            Map<String, Object> param = new HashMap<>();
            Menu pmenu = adminService.selectMenuByPId(menu.getMenuPreCode());
            param.put("buttonCode", menu.getMenuCode());
            param.put("isPermission", menu.getIsPermission());
            buttonViewsResponse.setPage(pmenu.getMenuName());
            buttonViewsResponse.setButtons(param);
            buttonViews.add(buttonViewsResponse);
        }
        return buttonViews;
    }

    /**
     * 根据员工id修改状态
     * @param id
     * @param status
     * @return
     */
    @GetMapping(value = "/updateStatusById")
    public CommonResult updateStatusById(@RequestParam("id") Integer id,@RequestParam("status") Integer status) {
        int updateStatusById = adminService.updateStatusById(id, status);
        if (0 < updateStatusById) {
            return CommonResult.success(updateStatusById);
        }
        return CommonResult.failed("该账户下的角色已关闭");
    }
}
